package config

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"
)

const (
	debugPath    = "log/debug.log"
	infoPath     = "log/info.log"
	errorPath    = "log/error.log"
	warrningPath = "log/warrn.log"
	sysPath      = "log/syslog.log"
	loglevel     = 1
)

//GLargeConfig ...
type GLargeConfig struct {
	DebugFile    string `ini:"debugfile"`
	InfoFile     string `ini:"infofile"`
	ErrorFile    string `ini:"errorfile"`
	WarrningFile string `ini:"warrningfile"`
	SysFile      string `ini:"sysfile"`
	LogLevel     int    `ini:"loglevel"`
}

//MysqlConfig ...
type MysqlConfig struct {
	DebugFile    string `ini:"debugfile"`
	InfoFile     string `ini:"infofile"`
	ErrorFile    string `ini:"errorfile"`
	WarrningFile string `ini:"warrningfile"`
	SysFile      string `ini:"sysfile"`
	LogLevel     int    `ini:"loglevel"`
}

//IniConfig ...
type IniConfig struct {
	GLargeConfig GLargeConfig `ini:"glogsys"`
	MysqlConfig  MysqlConfig  `ini:"mysql"`
}

func loadingIni(fileName string, v interface{}) (err error) {
	// 1. 判断传进来的v的类型是不是一个结构体
	t := reflect.TypeOf(v)
	if t.Kind() != reflect.Ptr && t.Kind() != reflect.Struct {
		return errors.New("该类型无法完成配置文件反射")
	}
	// 2. 打开文件流，判断打开的是否有问题
	fileobj, err := os.OpenFile(fileName, os.O_RDONLY, 0644)
	defer fileobj.Close()
	if err != nil {
		return err
	}
	reader := bufio.NewReader(fileobj)
	var struuctName string
	// var iniConfig IniConfig
	// 3. 一行行从文件流里面读 主for循环
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			break // 读到文件末尾
		}

		readByteTrim := strings.TrimSpace(string(line))
		// 4.  或者空行 ｜｜ 过滤注释 continue跳过
		if len(line) == 0 || strings.HasPrefix(readByteTrim, "#") || strings.HasPrefix(readByteTrim, ";") {
			continue
		}
		// 5. 判断是不是章节，不是的话也是continue
		if strings.HasPrefix(readByteTrim, "[") {
			if readByteTrim[0] == '[' && readByteTrim[len(readByteTrim)-1] == ']' {
				sectionName := readByteTrim[1 : len(readByteTrim)-1]
				for i := 0; i < t.Elem().NumField(); i++ {
					f := t.Elem().Field(i) // 传进来的t是个指针
					if sectionName == f.Tag.Get("ini") {
						struuctName = f.Name
						break
					}
				}
			} else {
				return errors.New("[] 必须成对出现")
			}
		} else {
			if struuctName == "" {
				continue
			} else {
				sStr := strings.Split(readByteTrim, "=")
				key := strings.TrimSpace(sStr[0])
				value := strings.TrimSpace(sStr[1])
				if key == "" || value == "" {
					return errors.New("synax error")
				}
				v1 := reflect.ValueOf(v)
				subStcuct := v1.Elem().FieldByName(struuctName)
				subType := subStcuct.Type()
				if subType.Kind() != reflect.Struct {
					err = fmt.Errorf("error 1")
					return err
				}
				var filedName string
				for i := 0; i < subType.NumField(); i++ {
					filed := subType.Field(i)
					subName := filed.Tag.Get("ini")
					if key == subName {
						filedName = filed.Name // 一定要是filed.name 不知道为何
						break
					}
				}
				fileValue := subStcuct.FieldByName(filedName)
				if filedName == "LogLevel" {
					// fmt.Printf("找到%s 的%s字段 %v \n", struuctName, filedName, fileValue)
					intValue, _ := strconv.ParseInt(value, 8, 8)
					fileValue.SetInt(intValue)
				} else {
					// fmt.Printf("找到%s 的%s字段 %s \n", struuctName, filedName, fileValue)
					fileValue.SetString(string(value))
				}
			}
			// 6. 键值对赋值
			// 1. 已等号赋值

		}
	}
	return nil
}

func loadingConfigDetail(reader io.Reader, config interface{}) {

}

//GenConfig1 is func
func GenConfig1(iniConfig *IniConfig) (glarge *GLargeConfig, err error) {
	ret := loadingIni("config/config.ini", iniConfig)
	return &iniConfig.GLargeConfig, ret
}

//GenConfig is func
// TODO: V2 反射获取配置文件
// func GenConfig() *IniConfig {
// 	var largeConfig = GLargeConfig{
// 		DebugFile:    debugPath,
// 		InfoFile:     infoPath,
// 		ErrorFile:    errorPath,
// 		WarrningFile: warrningPath,
// 		SysFile:      sysPath,
// 		LogLevel:     1,
// 	}
// 	var mysqlConfig MysqlConfig
// 	return &IniConfig{
// 		GLargeConfig: largeConfig,
// 		MysqlConfig:  mysqlConfig,
// 	}
// }
